package cn.datawin.routeserver.input.action;

import cn.datawin.bms.customer.entity.CstmCustomerEntity;
import cn.datawin.bms.customer.redis.CstmCustomerCmppRedisDto;
import cn.datawin.bms.customer.redis.CstmCustomerProviderChannelRedisDto;
import cn.datawin.bms.provider.redis.ProvProviderChannelRedisDto;
import cn.datawin.common.core.util.RedisUtils;
import cn.datawin.constant.ApiStatus;
import cn.datawin.constant.RedisPattern;
import cn.datawin.routeserver.input.machine.Basket;
import cn.datawin.routeserver.input.service.ErrorReportService;
import cn.datawin.sms.cmpp2.SmsDetailLog;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.WeightRandom;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.squirrelframework.foundation.fsm.UntypedAnonymousAction;
import org.squirrelframework.foundation.fsm.UntypedStateMachine;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 选择通道
 */
@Slf4j
public class SelectChannelAction extends BaseAction {
	@Override
	public void execute(Object ruleFrom, Object ruleTo, Object event, Object context, UntypedStateMachine stateMachine) {
		//1、获取smsDetailLog
		Basket basket = (Basket) context;
		CstmCustomerCmppRedisDto cstmCustomerCmppRedisDto = basket.getCstmCustomerCmppRedisDto();
		SmsDetailLog smsDetailLog = basket.getSmsDetailLog();
		Long cstmCustomerId = smsDetailLog.getCstmCustomerId();
		//2、根据cstmCustomerId查询通道(从redis中获取)
		String rKey = String.format(RedisPattern.CSTM_CUSTOMER_PROVIDER_CHANNEL_CACHE, cstmCustomerId);
		List<CstmCustomerProviderChannelRedisDto> dtos = RedisUtils.lGet(rKey, 0, -1);
		if(CollUtil.isEmpty(dtos)){
			log.info("cstmCustomerId:{} 没有绑定通道", cstmCustomerId);
			reportError(basket,ApiStatus._10004, smsDetailLog);
			return;
		}
		String channelSelectStrategy = cstmCustomerCmppRedisDto.getChannelSelectStrategy();
		List<String> keys = new ArrayList<>();
		dtos.forEach(dto -> {
			Long channelId = dto.getProviderChannelId();
			keys.add(String.format(RedisPattern.PROV_PROVIDER_CHANNEL_CACHE, channelId));
		});
		List<ProvProviderChannelRedisDto> provProviderChannelRedisDtos = RedisUtils.multiGet(keys);
		//省份、城市、运营商过滤
		String provinceCode = smsDetailLog.getProvince();
		String ispCode = smsDetailLog.getIspCode();
		List<ProvProviderChannelRedisDto> provProviderChannelRedisDtos1 = provProviderChannelRedisDtos.stream()
				.filter(dto -> dto.getProvinceCode().equals(provinceCode))
				.filter(dto -> dto.getIspCode().equals(ispCode)).toList();
		if(CollUtil.isEmpty(provProviderChannelRedisDtos1)){
			log.info("cstmCustomerId:{} 通道不匹配（省份、运营商不匹配）", cstmCustomerId);
			reportError(basket,ApiStatus._10005, smsDetailLog);
			return;
		}

		//price 价格优先  rate 占比分流  priority 优先级
		if("price".equals(channelSelectStrategy)){//价格优先
//			//根据价格排序
			provProviderChannelRedisDtos.sort(Comparator.comparing(ProvProviderChannelRedisDto::getPrice));
			ProvProviderChannelRedisDto provProviderChannelRedisDto = provProviderChannelRedisDtos.get(0);
			basket.setSelectChannel(provProviderChannelRedisDto);
		}
		if ("rate".equals(channelSelectStrategy)){//占比分流
			// 使用Hutool的WeightRandom实现权重随机选择
			WeightRandom<CstmCustomerProviderChannelRedisDto> weightRandom = new WeightRandom<>();
			dtos.forEach(dto -> weightRandom.add(dto, dto.getWeight()));
			CstmCustomerProviderChannelRedisDto selectedDto = weightRandom.next();

			ProvProviderChannelRedisDto provProviderChannelRedisDto = provProviderChannelRedisDtos.stream()
					.filter(dto -> dto.getId().equals(selectedDto.getProviderChannelId()))
					.findFirst()
					.orElse(null);
			basket.setSelectChannel(provProviderChannelRedisDto);
		}
		if ("priority".equals(channelSelectStrategy)){//优先级
			//根据优先级排序
			dtos.sort(Comparator.comparing(CstmCustomerProviderChannelRedisDto::getWeight));
			CstmCustomerProviderChannelRedisDto selectedDto = dtos.get(0);
			ProvProviderChannelRedisDto provProviderChannelRedisDto = provProviderChannelRedisDtos.stream()
					.filter(dto -> dto.getId().equals(selectedDto.getProviderChannelId()))
					.findFirst()
					.orElse(null);
			basket.setSelectChannel(provProviderChannelRedisDto);
		}
	}
}
